// EchoClient.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace CO::SpiFoundation::RoomFW;
using namespace CO::SpiControl::Protocol;
using namespace std;

int main(int argc, char* argv[])
{
try	{
	DynamicBindingManager::Instance();  // Make it destruct after PortRouter.  TODO:  Handle in RoomFW!!!
	GenericTestProtocol(true);	// Get the class factory initialized.

	G_LOGGER.setFile(true, "EchoClient.log");
	G_LOGGER.setVerbosity(CO::SpiFoundation::RoomFW::LV_ALL);
	if (!G_LOGGER.start())
	{
		cout << "Failed to start port router.  Enter any character to exit..." << endl;
		char c;
		cin >> c;
	}

	WSADATA WSAData;
	if (SOCKET_ERROR == ::WSAStartup(WORD MAKEWORD(2, 2), &WSAData))
	{
		SHOW_SOCKET_ERROR(false, "EchoClient", "::WSAStartup");
		cout << "Failed to initialize sockets.  Enter any character to exit..." << endl;
		char c;
		cin >> c;
	} 

	static const int portRouterListenPort = 27000;
	if (!PortRouter::Instance().start(portRouterListenPort, "127.0.0.1"))
	{
		cout << "Failed to start port router.  Enter any character to exit..." << endl;
		char c;
		cin >> c;
	}
	bool connected = false;
	static const int portRouterConnectPort = 27001;
	for (size_t i = 0; i < 10 && !connected; ++i)
	{
		connected = PortRouter::Instance().connect(portRouterConnectPort, "127.0.0.1");
	}
	if (!connected)
	{
		cout << "Failed to connect to remote port router.  Enter any character to exit..." << endl;
		char c;
		cin >> c;
	}

#define EXTRA_SERVER 0
#if EXTRA_SERVER
	// Start our own server
	IEchoServerSP server = IEchoServer::Create("LOCAL_ECHO_SERVER");
	if (server->start())
	{
		// Bind to our server and tell it to bind to remote server.
		EventPortal portal("Echo Client Portal");
		VERIFY(portal.initialize());

		BindingSP binding;
		for (size_t i = 0; i < 10; ++i)
		{
			binding = portal.dynamicBind("LOCAL_ECHO_SERVER_PORT_ECHO_IN", CTID_NULL, true);
			if (binding)
			{
				break;
			}
			else
			{
				::Sleep(250);
			}
		}
		if (binding)
		{
			portal.sendMessage(GenericTestProtocol::IN_DYNAMIC_BIND,
				PAYLOAD2(DynamicBindPayload, IEchoServer::PORT_ECHO_IN, "ECHO_SERVER_PORT_ECHO_OUT"));
		}
	}
	else
	{
		cout << "Failed to start server.  Enter any character to exit..." << endl;
		char c;
		cin >> c;
	}
#endif

	EventPortal portal("Echo Client Portal");
	VERIFY(portal.initialize());

	// Wait for remote registration.
	BindingSP binding;
	for (size_t i = 0; i < 10; ++i)
	{
		binding = portal.dynamicBind("ECHO_SERVER_PORT_ECHO_IN", CTID_NULL, true);
		if (binding)
		{
			break;
		}
		else
		{
			::Sleep(250);
		}
	}
	if (binding)
	{
		string str;
		do
		{
			cout << "enter a string to echo (/exit to exit:" << endl;
			cin >> str;

			if (str != "/exit")
			{
				// Regular send.  One reply and one send back.
				portal.sendMessage(GenericTestProtocol::IN_STRING_MESSAGE1, PAYLOAD1(StringPayload, str));
				portal.wait();
				RoomMessageSP reply = portal.getMessage();
				ASSERT(reply);
				StringPayloadSP payload = ::boost::dynamic_pointer_cast<StringPayload>(reply->payload());
				cout << payload->value() << endl;

				portal.wait();
				reply = portal.getMessage();
				ASSERT(reply);
				payload = ::boost::dynamic_pointer_cast<StringPayload>(reply->payload());
				ASSERT(payload);
				cout << payload->value() << endl;


				// Invoke.  One reply and one send back.
				reply = portal.invoke(1000, GenericTestProtocol::IN_STRING_MESSAGE1, PAYLOAD1(StringPayload, str));
				ASSERT(reply);
				payload = ::boost::dynamic_pointer_cast<StringPayload>(reply->payload());
				ASSERT(payload);
				cout << payload->value() << endl;

				portal.wait();
				reply = portal.getMessage();
				ASSERT(reply);
				payload = ::boost::dynamic_pointer_cast<StringPayload>(reply->payload());
				ASSERT(payload);
				cout << payload->value() << endl;
			}
			else
			{
				SimpleEvent stopEvent;
				VERIFY(stopEvent.create(false, false, "ECHO_SERVER_STOP_EVENT"));
				VERIFY(stopEvent.set());
#if EXTRA_SERVER
				server->stop();
#endif
			}
		} while (str != "/exit");
		binding.reset();
	}
	else
	{
		cout << "Failed to bind to server.  Enter any character to exit..." << endl;
		char c;
		cin >> c;
	}
} catch(std::exception& e)
{
	cout << endl;
	cout << "Caught " << e.what() << ".  Enter any character to exit..." << endl;
	char c;
	cin >> c;
}
catch (...)
{
	cout << "Caught ...  Enter any character to exit..." << endl;
	char c;
	cin >> c;
}
	PortRouter::Instance().stop();
	SHOW_SOCKET_ERROR((SOCKET_ERROR != WSACleanup()), "EchoClient", "::WSACleanup");
	return 0;
}

